package jp.cane.android.luciferblue;

import java.util.Calendar;

import android.app.Activity;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.Html;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.ToggleButton;

public class MainActivity extends Activity {
	final static private int FIRST = 0;
	final static private int REQUEST_POLLING = 1;
	final static private int REQUEST_SCAN = 2;
	final static private String TAG = "MainActivity";

	private MainServiceObserver mObserver;
	private ServiceConnection mConnection;
	private MyBindService mService;
	private Handler handler = new Handler();
	private Thread timeThread = null;
	private boolean mBind = false;

	private BluetoothSocket socket = null;

	private String strtext = "";

	private boolean echo = true;

	private Thread pollingThread = null;
	private String pollingStrings = "";
	private int pollingInterval = 1;
	private boolean pollingLoop = false;

	private Calendar lastReceivedTime = Calendar.getInstance();

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Button button = (Button) findViewById(R.id.send);
		button.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				if (socket != null) {
					EditText edit = (EditText) findViewById(R.id.editText1);
					String str = edit.getText().toString();
					send(str);
					edit.setText("");
				}
			}
		});

		final ToggleButton polling = (ToggleButton) findViewById(R.id.polling);
		polling.setOnCheckedChangeListener(new OnCheckedChangeListener() {
			public void onCheckedChanged(CompoundButton buttonView,
					boolean isChecked) {
				if (pollingThread != null) {
					Thread thread = pollingThread;
					pollingThread = null;
					thread.interrupt();
					polling.setChecked(false);
				} else {
					pollingThread = new Thread() {
						public void run() {
							try {
								String[] strs = pollingStrings.split("\n");
								do {
									for (String str : strs) {
										if (str != strs[0]) {
											try {
												Thread.sleep(pollingInterval * 1000);
											} catch (InterruptedException e) {
											}
										}
										if (pollingThread == null) {
											return;
										}
										send(str);
									}
									if (pollingLoop) {
										try {
											Thread.sleep(pollingInterval * 1000);
										} catch (InterruptedException e) {
										}
									}
								} while (pollingLoop);
							} finally {
								handler.post(new Runnable() {
									public void run() {
										polling.setChecked(false);
									}
								});
							}
						};
					};
					polling.setChecked(true);
					pollingThread.start();
				}
			}
		});

		this.timeThread = new Thread() {
			public void run() {
				while (true) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

					final Calendar calendar = Calendar.getInstance();

					final int year = calendar.get(Calendar.YEAR);
					final int month = calendar.get(Calendar.MONTH);
					final int day = calendar.get(Calendar.DAY_OF_MONTH);
					final int hour = calendar.get(Calendar.HOUR_OF_DAY);
					final int minute = calendar.get(Calendar.MINUTE);
					final int second = calendar.get(Calendar.SECOND);
					final int ms = calendar.get(Calendar.MILLISECOND);

					final String time = ""
							+ ("0" + hour).substring(("0" + hour).length() - 2)
							+ ":"
							+ ("0" + minute)
									.substring(("0" + minute).length() - 2)
							+ ":"
							+ ("0" + second)
									.substring(("0" + second).length() - 2);

					handler.post(new Runnable() {
						public void run() {
							TextView text = (TextView) findViewById(R.id.time);
							text.setText(time);
						}
					});
				}
			};
		};
		this.timeThread.start();

		// ActivityにServiceからのCallbackを受け取るためのCallback interfaceを実装
		mObserver = new MainServiceObserver.Stub() {
			// Callback methodを実装
			public void onDataReady(String message) throws RemoteException {
				Log.d(TAG, "onDataReady called by "
						+ Thread.currentThread().getName());
				// AIDLに定義したmethodはBinder thread上で実行されるのでUIの操作は出来ない
				// UIをupdateするためHandlerを使用
				change(message);
			}

			public void appendLog(String message) throws RemoteException {
				append(message);
			}
		};

		// ServiceConnectionを拡張したclassを実装する
		mConnection = new ServiceConnection() {
			// ServiceConnection#onServiceConntected()の引数で渡される
			// IBinder objectを利用しAIDLで定義したInterfaceを取得
			public void onServiceConnected(ComponentName name, IBinder service) {
				mService = MyBindService.Stub.asInterface(service);
				// Toast.makeText(
				// mContext,
				// "ServiceConnection onServiceConnected called by "
				// + Thread.currentThread().getName(),
				// Toast.LENGTH_LONG).show();
				try {
					// 取得したinterfaceを利用しService用のAIDL
					// fileで定義されたmethodでObserver登録/解除
					mService.setObserver(mObserver);
				} catch (RemoteException e) {
				}
				mBind = true;
			}

			// Serviceを動かしてるProcessがcrashするかkillされない限り呼ばれない
			public void onServiceDisconnected(ComponentName name) {
				mService = null;
				// Toast.makeText(
				// mContext,
				// "ServiceConnection onServiceDisConnected calle by "
				// + Thread.currentThread().getName(),
				// Toast.LENGTH_LONG).show();
			}
		};

		// Intentを作成
		Intent intent = new Intent(this, MainService.class);
		startService(intent);
		// Context#bindService()でServiceとのConnectionを確率
		bindService(intent, mConnection, BIND_AUTO_CREATE);
	}

	@Override
	protected void onDestroy() {
		if (mBind) {
			try {
				// 取得したinterfaceを利用しService用のAIDL fileで定義されたmethodでObserver登録/解除
				mService.removeObserver(mObserver);
			} catch (RemoteException e) {
			}
			// Context#UnbindService()でServiceとのConnectionを破棄
			unbindService(mConnection);
			mBind = false;
		}
		if (this.timeThread != null) {
			this.timeThread.interrupt();
			this.timeThread = null;
		}
		if (this.pollingThread != null) {
			this.pollingThread.interrupt();
			this.pollingThread = null;
		}
		super.onDestroy();
	}

	protected void send(String str) {
		MainService.send(str);
		if (echo) {
			append("<font color='blue'>" + str + "</font>");
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		{
			MenuItem item = menu.add(0, FIRST, 0, R.string.scan);
			item.setOnMenuItemClickListener(new OnMenuItemClickListener() {
				public boolean onMenuItemClick(MenuItem item) {
					Intent intent = new Intent(MainActivity.this,
							DiscoveryActivity.class);
					startActivityForResult(intent, REQUEST_SCAN);
					return true;
				}
			});
		}
		{
			MenuItem item = menu.add(0, FIRST + 1, 0, R.string.echo);
			item.setOnMenuItemClickListener(new OnMenuItemClickListener() {
				public boolean onMenuItemClick(MenuItem item) {
					MainActivity.this.echo = !MainActivity.this.echo;
					return true;
				}
			});
		}
		{
			MenuItem item = menu.add(0, FIRST + 2, 0, R.string.setuppolling);
			item.setOnMenuItemClickListener(new OnMenuItemClickListener() {
				public boolean onMenuItemClick(MenuItem item) {
					Intent intent = new Intent(MainActivity.this,
							PollingActivity.class);
					intent.putExtra("pollingStrings", pollingStrings);
					intent.putExtra("pollingInterval", pollingInterval);
					intent.putExtra("pollingLoop", pollingLoop);
					startActivityForResult(intent, REQUEST_POLLING);
					return true;
				}
			});
		}

		return true;
	}

	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == REQUEST_POLLING && resultCode == RESULT_OK) {
			Bundle extras = data.getExtras();

			pollingStrings = (extras.getString("pollingStrings"));
			pollingInterval = (extras.getInt("pollingInterval"));
			pollingLoop = (extras.getBoolean("pollingLoop"));
		} else if (requestCode == REQUEST_SCAN && resultCode == RESULT_OK) {
			BluetoothDevice device = null;
			if (getIntent().getExtras() != null) {
				device = (BluetoothDevice) getIntent().getExtras().get(
						BluetoothDevice.EXTRA_DEVICE);
				MainService.device = device;
				// append("log:" + device);
				Intent intent = new Intent(this, MainService.class);
				startService(intent);
			}
		}
	}

	private void append(final String str) {
		strtext = str + "<br />\n" + strtext;
		this.handler.post(new Runnable() {
			public void run() {
				TextView text = (TextView) findViewById(R.id.text);
				text.setText(Html.fromHtml(strtext));
			}
		});
	}

	private void change(final String str) {
		this.handler.post(new Runnable() {
			public void run() {
				{
					final Calendar calendar = MainActivity.this.lastReceivedTime;

					final int year = calendar.get(Calendar.YEAR);
					final int month = calendar.get(Calendar.MONTH);
					final int day = calendar.get(Calendar.DAY_OF_MONTH);
					final int hour = calendar.get(Calendar.HOUR_OF_DAY);
					final int minute = calendar.get(Calendar.MINUTE);
					final int second = calendar.get(Calendar.SECOND);
					final int ms = calendar.get(Calendar.MILLISECOND);

					// Log.v("year/month/day hour:minute:second", year + "/"
					// + (month + 1) + "/" + day + "/" + " " + hour + ":"
					// + minute + ":" + second + "." + ms);

					final String time = ""
							+ ("0" + hour).substring(("0" + hour).length() - 2)
							+ ":"
							+ ("0" + minute).substring(("0" + minute).length() - 2)
							+ ":"
							+ ("0" + second).substring(("0" + second).length() - 2);

					TextView text = (TextView) findViewById(R.id.lasttime);
					text.setText(time);
				}
				{
					TextView text = (TextView) findViewById(R.id.textView1);
					text.setText(str);
				}
			}
		});
	}
}